/*
 * s_cc2640r2f_gatt_profile.c
 *
 *  Created on: Sep 25, 2019
 *      Author: hemingway
 */
#include "h_cc2640r2f_define.h"
#include "s_cc2640r2f_gatt_profile.h"

#include <stdio.h>
#include <string.h>
#include <icall.h>

#include "util.h"

#include "h_cc2640r2f_uart.h"
#include "simple_peripheral_oad_offchip.h"

unsigned char notify_data[GATT_SERVICE1_CHAR1DATALEN];
unsigned short notify_data_len = 0U;

static unsigned char *gattProfileGetRspDataPoint(void)
{
//    return H_CC2640R2F_UARTRxBuffer;
    return notify_data;
}

static unsigned short gattProfileGetRspDataLength(void)
{
//    return H_CC2640R2F_UARTRxBufferLength;
    return notify_data_len;
}

static void gattProfileGetRqstData(unsigned char *data, unsigned short len)
{
    H_CC2640R2F_UART_TxBuff(data, len);
}

/*
 *  Gatt service1 UUID
 * */
#if GATT_UUID_LEN == ATT_BT_UUID_SIZE
const unsigned char gattService1UUID[ATT_BT_UUID_SIZE] =
{
 LO_UINT16(GATT_SERVICE1_UUID), HI_UINT16(GATT_SERVICE1_UUID)
};
#else
const unsigned char gattService1UUID[ATT_UUID_SIZE] =
{
 TI_BASE_UUID_128(GATT_SERVICE1_UUID)
};
#endif

/*
 *  Gatt service1 character1 uuid
 * */
#if GATT_UUID_LEN == ATT_BT_UUID_SIZE
const unsigned char gattService1Char1UUID[ATT_BT_UUID_SIZE] =
{
 LO_UINT16(GATT_SERVICE1_CHAR1UUID), HI_UINT16(GATT_SERVICE1_CHAR1UUID)
};
#else
const unsigned char gattService1Char1UUID[ATT_UUID_SIZE] =
{
 TI_BASE_UUID_128(GATT_SERVICE1_CHAR1UUID)
};
#endif

/* 
  Gatt Service1 character2 uuid
*/
// #if GATT_UUID_LEN == ATT_BT_UUID_SIZE
// const unsigned char gattService1Char2UUID[ATT_BT_UUID_SIZE] =
// {
//  LO_UINT16(GATT_SERVICE1_CHAR2UUID), HI_UINT16(GATT_SERVICE1_CHAR2UUID)
// };
// #else
// const unsigned char gattService1Char2UUID[ATT_UUID_SIZE] =
// {
//  TI_BASE_UUID_128(GATT_SERVICE1_CHAR2UUID)
// };
// #endif

/*
 *  Gatt service1 profile Callbacks
 * */
static gattProfileCallback_t *pGattService1ProfileCallback = NULL;

/*
 *  Gatt service1 GATT Attribute Type
 * */
static const gattAttrType_t gattService1AttrType =
{
 GATT_UUID_LEN, gattService1UUID
};

//////////////////////////////////////////

/*
 *  Gatt service1 char1 properities
 * */
static const uint8 gattServer1Char1Props = \
        GATT_PROP_WRITE | GATT_PROP_NOTIFY;
/*
 *  Gatt service1 char1 data
 * */
unsigned char gattService1Char1Data[GATT_SERVICE1_CHAR1DATALEN];
volatile unsigned short gattService1Char1Datalen = 0U;

/*
 *  Gatt service1 char1 description
 * */
static const uint8 gattService1Char1Desp[] = "App\0";

/*
 *  Gatt service1 char1 Client Characteristic Configuration.
 * */
static gattCharCfg_t *gattService1Char1Cfg = NULL;

//////////////////////////////////////////

// /*
//  *  Gatt service1 char2 properities
//  * */
// static const uint8 gattServer1Char2Props = \
//         GATT_PROP_READ | GATT_PROP_NOTIFY;
// /*
//  *  Gatt service1 char2 data
//  * */
// unsigned char gattService1Char2Data[GATT_SERVICE1_CHAR2DATALEN];
// volatile unsigned short gattService1Char2Datalen = 0U;

// /*
//  *  Gatt service1 char2 description
//  * */
// static const uint8 gattService1Char2Desp[] = "Para\0";

// /*
//  *  Gatt service1 char2 Client Characteristic Configuration.
//  * */
// static gattCharCfg_t *gattService1Char2Cfg = NULL;

//////////////////////////////////////////

/*
 *  GATT Attribute
 * */

static gattAttribute_t gattService1Attr[] =
{
 //Primary service1
 {
  {ATT_BT_UUID_SIZE, primaryServiceUUID},
  GATT_PERMIT_READ,
  0,
  (unsigned char *)&gattService1AttrType
 },

 //////////////////////////////////////////

 //Service1 char1 declaration
 {
  { ATT_BT_UUID_SIZE, characterUUID },
  GATT_PERMIT_READ,
  0,
  &gattServer1Char1Props
 },

 //Service1 char1 data
 {
  {GATT_UUID_LEN, gattService1Char1UUID},
  GATT_PERMIT_WRITE,                        //Data could just write
  0,
  gattService1Char1Data
 },

 //Service1 char1 configuration -- notify
 {
  {ATT_BT_UUID_SIZE, clientCharCfgUUID},
  GATT_PERMIT_READ | GATT_PERMIT_WRITE,
  0,
  (unsigned char *)&gattService1Char1Cfg
 },

 //Service1 char1 description
 {
  {ATT_BT_UUID_SIZE, charUserDescUUID},
  GATT_PERMIT_READ,
  0,
  gattService1Char1Desp
 },

 //////////////////////////////////////////

 // //Service1 char2 declaration
 // {
 //  { ATT_BT_UUID_SIZE, characterUUID },
 //  GATT_PERMIT_READ,
 //  0,
 //  &gattServer1Char2Props
 // },

 // //Service1 char2 data
 // {
 //  {GATT_UUID_LEN, gattService1Char2UUID},
 //  GATT_PERMIT_READ,                        //Data could just write
 //  0,
 //  gattService1Char2Data
 // },

 // //Service1 char2 configuration -- notify
 // {
 //  {ATT_BT_UUID_SIZE, clientCharCfgUUID},
 //  GATT_PERMIT_READ | GATT_PERMIT_WRITE,
 //  0,
 //  (unsigned char *)&gattService1Char2Cfg
 // },

 // //Service1 char2 description
 // {
 //  {ATT_BT_UUID_SIZE, charUserDescUUID},
 //  GATT_PERMIT_READ,
 //  0,
 //  gattService1Char2Desp
 // },

};

static bStatus_t gattProfileReadAttrCallback(unsigned short connHandle, \
                                             gattAttribute_t *pAttr, \
                                             unsigned char *pdata, \
                                             unsigned short *plength, \
                                             unsigned short offset, \
                                             unsigned short maxlen, \
                                             unsigned char method)
{
    bStatus_t status = SUCCESS;
    unsigned short uuid;

    //Check offset
    if(offset > 0)
    {
        return ATT_ERR_ATTR_NOT_LONG;
    }

    //128bit
    if(ATT_UUID_SIZE == pAttr->type.len)
    {
        uuid = BUILD_UINT16(pAttr->type.uuid[12], pAttr->type.uuid[13]);
    }
    else if(ATT_BT_UUID_SIZE == pAttr->type.len)    //16bit
    {
        uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
    }
    else
    {
        *plength = 0;
        status = ATT_ERR_INVALID_HANDLE;

        return status;
    }

   // printf("r--uuid:%x\r\n", uuid);
    switch(uuid)
    {
//        printf("gattProfileReadAttrCallback\r\n");
        case GATT_SERVICE1_CHAR1UUID:

              // *plength = gattService1Char1Datalen;
              // memcpy(pdata, gattService1Char1Data, *plength);
           *plength = gattProfileGetRspDataLength();
           memcpy(pdata, gattProfileGetRspDataPoint(), *plength);

            break;

//         case GATT_SERVICE1_CHAR2UUID:
// //            S_LockControl_Ask2GetBAT(0);
//         // printf("char 2\r\n");
//             *plength = gattService1Char2Datalen;
//             memcpy(pdata, gattService1Char2Data, *plength);
//             break;

        default:
            *plength = 0U;
            status = ATT_ERR_ATTR_NOT_FOUND;
            break;
    }

    return status;
}

static bStatus_t gattProfileWriteAttrCallback(unsigned short connHandle, \
                                             gattAttribute_t *pAttr, \
                                             unsigned char *pdata, \
                                             unsigned short length, \
                                             unsigned short offset, \
                                             unsigned char method)
{
    bStatus_t status = SUCCESS;
    unsigned char notifyApp = 0xFF;
    unsigned short uuid;

    // If attribute permissions require authorization to write, return error
    if ( gattPermitAuthorWrite( pAttr->permissions ) )
    {
      // Insufficient authorization
      return ( ATT_ERR_INSUFFICIENT_AUTHOR );
    }

//    printf("--gattProfileWriteAttrCallback\r\n");

    // 128 bit
    if(ATT_UUID_SIZE == pAttr->type.len)
    {
//        printf("--128bit\r\n");
        uuid = BUILD_UINT16( pAttr->type.uuid[12], pAttr->type.uuid[13]);
    }
    // 16 bit
    else if(ATT_BT_UUID_SIZE == pAttr->type.len)   //16bit
    {
//        printf("--16bit\r\n");
        uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
    }
    else
    {
        status = ATT_ERR_INVALID_HANDLE;

        return status;
    }

//    printf("--uuid is 0x%d\r\n", pAttr->type.len);
    // printf("w--uuid: %x\r\n", uuid);


    switch(uuid)
    {
        case GATT_SERVICE1_CHAR1UUID:
            if(offset == 0)
            {
                if(length > GATT_SERVICE1_CHAR1DATALEN)
                {
                    status = ATT_ERR_INVALID_VALUE_SIZE;
                }
            }
            else
            {
                status = ATT_ERR_ATTR_NOT_LONG;
            }

            if(SUCCESS == status)
            {
                unsigned char *pCurData = (unsigned char *)pAttr->pValue;
                VOID memcpy(pCurData, pdata, length);

                if(pAttr->pValue == gattService1Char1Data)
                {
                    gattService1Char1Datalen = length;
                    notifyApp = GATT_SERVICE1_CHAR1;
                }

               // S_CC2640R2F_Gatt_Profile_Handle_BLE_ReceivedData(GATT_SERVICE1_CHAR1);
            }

            break;

        case GATT_CLIENT_CHAR_CFG_UUID:
        // printf("--noti\r\n");
            status = GATTServApp_ProcessCCCWriteReq(connHandle, \
                        pAttr, pdata, length, \
                        offset, GATT_CLIENT_CFG_NOTIFY);
            break;

        default:
            status = ATT_ERR_ATTR_NOT_FOUND;
            break;

    }

    if((notifyApp != 0xFF) && pGattService1ProfileCallback && \
            pGattService1ProfileCallback->pfnGattProfileChange)
    {
        pGattService1ProfileCallback->pfnGattProfileChange(notifyApp);
    }

    return status;
}

const gattServiceCBs_t gattServiceCallback =
{
 gattProfileReadAttrCallback,
 gattProfileWriteAttrCallback,
 NULL
};

bStatus_t S_CC2640R2F_Gatt_Profile_AddService(unsigned int service)
{
    unsigned char status;
    unsigned char gattServiceCharTableSize = sizeof(gattCharCfg_t) * \
                                              linkDBNumConns * \
                                              GATT_SERVICE1_CHAR_NUM;

    gattService1Char1Cfg = (gattCharCfg_t *)ICall_malloc(gattServiceCharTableSize);

    if(NULL == gattService1Char1Cfg)
    {
        return bleMemAllocError;
    }
    // gattService1Char2Cfg = gattService1Char1Cfg + linkDBNumConns;


    //Initialize client characteristic configuration attributes
    GATTServApp_InitCharCfg(INVALID_CONNHANDLE, gattService1Char1Cfg);
    // GATTServApp_InitCharCfg(INVALID_CONNHANDLE, gattService1Char2Cfg);

    if(service & GATT_PROFILE_SERVICE)
    {
        //Register gatt attribute list and callback with gatt serser
        status = GATTServApp_RegisterService(gattService1Attr,
                                             GATT_NUM_ATTRS( gattService1Attr ),
                                             GATT_MAX_ENCRYPT_KEY_SIZE,
                                             &gattServiceCallback);
    }
    else
    {
        status = SUCCESS;
    }

    return status;
}

bStatus_t gattProfileRegisterAppCallback(gattProfileCallback_t *gattCallback)
{
    if(gattCallback)
    {
        pGattService1ProfileCallback = gattCallback;
        return SUCCESS;
    }
    else
    {
        return bleAlreadyInRequestedMode;
    }
}

bStatus_t S_CC2640R2F_Gatt_Profile_NotifyOutData(unsigned char paraID, \
                                                 unsigned char *data, \
                                                 unsigned char length)
{
    bStatus_t status = SUCCESS;
    switch(paraID)
    {
        case GATT_SERVICE1_CHAR1:
            // See if Notification has been enabled
            GATTServApp_ProcessCharCfg(gattService1Char1Cfg, \
                                       gattService1Char1Data, FALSE, \
                                       gattService1Attr, \
                                        GATT_NUM_ATTRS(gattService1Attr), \
                                        INVALID_TASK_ID, \
                                        gattProfileReadAttrCallback );
    }

    return status;
}

bStatus_t S_CC2640R2F_Gatt_Profile_Handle_BLE_ReceivedData(unsigned char paramID)
{
    bStatus_t status = SUCCESS;

    switch(paramID)
    {
        case GATT_SERVICE1_CHAR1:
            gattProfileGetRqstData(gattService1Char1Data, gattService1Char1Datalen);
            // S_Auto_Plant_Msg_Handle(gattService1Char1Data, gattService1Char1Datalen);
//             S_CSAM_Msg_Handle(gattService1Char1Data, \
                                      gattService1Char1Datalen);
            // S_LockControl_Ask2NewBLEMsg(gattService1Char1Data, gattService1Char1Datalen);
            break;

        default:
            break;

    }

    return status;
}
